//go:build sql_integration

package m189tom190

import (
	"context"
	"testing"
	"time"

	"github.com/stackrox/rox/generated/storage"
	oldSchema "github.com/stackrox/rox/migrator/migrations/m_189_to_m_190_vulnerability_requests_add_name/schema/old"
	previousStore "github.com/stackrox/rox/migrator/migrations/m_189_to_m_190_vulnerability_requests_add_name/store/previous"
	updatedStore "github.com/stackrox/rox/migrator/migrations/m_189_to_m_190_vulnerability_requests_add_name/store/updated"
	pghelper "github.com/stackrox/rox/migrator/migrations/postgreshelper"
	"github.com/stackrox/rox/migrator/types"
	"github.com/stackrox/rox/pkg/postgres/pgutils"
	"github.com/stackrox/rox/pkg/protoconv"
	"github.com/stackrox/rox/pkg/sac"
	"github.com/stackrox/rox/pkg/search"
	"github.com/stackrox/rox/pkg/uuid"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/stretchr/testify/suite"
)

type migrationTestSuite struct {
	suite.Suite

	db  *pghelper.TestPostgres
	ctx context.Context
}

func TestMigration(t *testing.T) {
	suite.Run(t, new(migrationTestSuite))
}

func (s *migrationTestSuite) SetupSuite() {
	s.ctx = sac.WithAllAccess(context.Background())
	s.db = pghelper.ForT(s.T(), false)

	pgutils.CreateTableFromModel(s.ctx, s.db.GetGormDB(), oldSchema.CreateTableVulnerabilityRequestsStmt)
}

func (s *migrationTestSuite) TestMigration() {
	layout := "2006/01/02"
	jun29, err := time.Parse(layout, "2023/06/29")
	require.NoError(s.T(), err)
	jul29, err := time.Parse(layout, "2023/07/29")
	require.NoError(s.T(), err)
	aug29, err := time.Parse(layout, "2023/08/29")
	require.NoError(s.T(), err)
	aug30, err := time.Parse(layout, "2023/08/30")
	require.NoError(s.T(), err)
	sept29, err := time.Parse(layout, "2023/09/29")
	require.NoError(s.T(), err)

	vulnReqs := []*storage.VulnerabilityRequest{
		testRequestNameFakeVulnReq(aug29, "bruce wayne"),
		testRequestNameFakeVulnReq(aug30, "bruce wayne"),
		testRequestNameFakeVulnReq(sept29, "bruce wayne"),
		testRequestNameFakeVulnReq(sept29, "bruce thomas wayne"),
		testRequestNameFakeVulnReq(jun29, ""),
		testRequestNameFakeVulnReq(sept29, "bruce   thomas wayne  "),
	}
	jul1 := testRequestNameFakeVulnReq(jul29, "")
	jul1.Name = "BW-230729-100"
	jul2 := testRequestNameFakeVulnReq(jul29, "bruce   thomas wayne  ")
	jul2.Name = "BW-230729-200"
	vulnReqs = append(vulnReqs, jul1, jul2)

	expectedRequestNames := []string{
		"SYS-230629-1",
		"BW-230729-100",
		"BW-230729-200",
		"BW-230829-1",
		"BW-230830-2",
		"BW-230929-1",
		"BW-230929-2",
		"BW-230929-3",
		"BW-230929-4",
	}

	store := previousStore.New(s.db)
	require.NoError(s.T(), store.UpsertMany(s.ctx, vulnReqs))

	dbs := &types.Databases{
		GormDB:     s.db.GetGormDB(),
		PostgresDB: s.db.DB,
		DBCtx:      s.ctx,
	}

	s.Require().NoError(migration.Run(dbs))

	newStore := updatedStore.New(s.db)
	updatedVulnReqs, err := newStore.GetByQuery(s.ctx, search.EmptyQuery())
	assert.NoError(s.T(), err)
	for _, req := range updatedVulnReqs {
		assert.NotEmpty(s.T(), req.GetName())
		assert.Contains(s.T(), expectedRequestNames, req.GetName())
	}
}

func testRequestNameFakeVulnReq(createdAt time.Time, userName string) *storage.VulnerabilityRequest {
	return &storage.VulnerabilityRequest{
		Id: uuid.NewV4().String(),
		Requestor: &storage.SlimUser{
			Name: userName,
		},
		CreatedAt: protoconv.ConvertTimeToTimestamp(createdAt.UTC()),
	}
}
